#!/usr/bin/env python2
#-*- coding: utf-8 -*-

import sys
import hashlib
import random
import time
import datetime
import traceback

from sqlalchemy import exc as sql_exc

# from repoze.lru import CacheMaker

from Ump.common import exception, log
from Ump.common.objcache import ObjectCache, cache_get_or_create

from Ump.objs.db import models
from Ump.objs.manager_base import Manager
from Ump.objs.session_wrapper import _sw

LOG = log.get_logger('Ump.objs.pool.manager')

def encode_passwd(plain_text):
    return hashlib.md5(plain_text.strip()).hexdigest()


def _load_from_db(token_name, expire=24*60*60):
    try:
        now = datetime.datetime.now()
        token = _sw.get_one(model=models.Token, id_or_spec={'token': token_name})
        if token:
            # TODO expire
            expire_delta = datetime.timedelta(seconds=expire)
            diff = now - token.created_at
            if diff > expire_delta:
#                ObjectCache.delete(token_name)
                LOG.info("token is expired,deleted: %s" % (token.token))

                token.delete()
                token = None
                # DB will rollback
                raise exception.TokenExpire(expire=expire)
        if token:
            return {'token': token.token, 'user_id': token.user_id, 'username': token.user.name}
    except sql_exc.InvalidRequestError, e:
        traceback.print_exc()
        raise
    except Exception, e:
        raise


@models.add_model(models.Token)
class TokenManager(Manager):

    def __init__(self):
        super(TokenManager, self).__init__()

    def create(self, params):
        username = params.get('username')
        plain = params.get('password')

        user = _sw.get_user(username=username)
        if not user:
            raise exception.UserNotFound(username=username)

        password = encode_passwd(plain)
        user = _sw.get_one(model=models.User, id_or_spec={'name': username, 'password': password})
        if not user:
            raise exception.UserPasswordError(username=username)
        
        return self._create_token_with_user(user)

    def _create_token_with_user(self, user):
        token = _sw.get_one(models.Token, id_or_spec={'user_id': user.id})
        if token:
            return token

        token_name = self._make_token()

        # TODO
        values = {
            'user_id': user.id,
            'token': token_name,
        }

        token = models.Token(values).save()

        # TODO 201 created
        return token

    def delete(self, params):
        """
        :param params:
        :return:

        .. versionadded: 1.0.1
        .. deprecated:: 1.0.1
        """
        _id = params['id']

        token = _sw.get_one(model=models.Token, id_or_spec={'id': _id})
        if not token:
            raise exception.TokenNotfound(token=token)

        return token.delete()

    def _make_token(self):
        r = random.random()
        return str(hashlib.sha1('%f%s' % (r, time.ctime())).hexdigest())

    @staticmethod
    def load(token_name):
        return TokenManager.load_from_db(token_name)

    @staticmethod
    def load_from_db(token_name, expire=24*60*60):
        # token = cache_get_or_create(token_name, _load_from_db, token_name=token_name, expire=expire, _sw=_sw)
        # ObjectCache.scan()
        # print 'token', token
        return _load_from_db(token_name, expire=expire)

    def expire(self, timeout=None):
        pass


if __name__ == '__main__':
    pass
